home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2004 April / Gamestar_61_2004-04_dvdb.iso / DVDStar / Editace / hltp.exe / {app} / Source Code / Zoners Half-Life Tools / netvis / packet.cpp < prev    next >
C/C++ Source or Header  |  2001-04-25  |  40KB  |  1,079 lines

  1. #include "netvis.h"
  2.  
  3. #include "zlib.h"
  4.  
  5. portal_t*       GetPortalPtr(long index);
  6. int             GetNextPortalIndex(void);
  7.  
  8. static ReferenceCounter s_OutstandingSyncRequests;
  9. static ReferenceCounter s_IdleCounter;
  10. static long     s_PortalArray[PORTAL_ARRAY_MAX_SIZE];
  11. long            g_PortalArrayIndex = 0;                    // Current offset
  12. static Mutex    s_PortalArrayLock;                         // protects g_PortalArrayIndex, s_PortalArray
  13. bool            g_NetvisAbort = false;
  14.  
  15. static void     Handle_VIS_LOGIN(VIS_LOGIN* packet, NetvisSession* socket);
  16. static void     Handle_VIS_LOGIN_NAK(VIS_LOGIN_NAK* packet, NetvisSession* socket);
  17. static void     Handle_VIS_LOGIN_ACK(VIS_LOGIN_ACK* packet, NetvisSession* socket);
  18.  
  19. static void     Handle_VIS_WANT_BSP_DATA(VIS_WANT_BSP_DATA* packet, NetvisSession* socket);
  20. static void     Handle_VIS_BSP_DATA_NAK(VIS_BSP_DATA_NAK* packet, NetvisSession* socket);
  21. static void     Handle_VIS_BSP_DATA(VIS_BSP_DATA* packet, NetvisSession* socket);
  22. static void     Handle_VIS_BSP_NAME(VIS_BSP_NAME* packet, NetvisSession* socket);
  23.  
  24. static void     Handle_VIS_WANT_PRT_DATA(VIS_WANT_PRT_DATA* packet, NetvisSession* socket);
  25. static void     Handle_VIS_PRT_DATA_NAK(VIS_PRT_DATA_NAK* packet, NetvisSession* socket);
  26. static void     Handle_VIS_PRT_DATA(VIS_PRT_DATA* packet, NetvisSession* socket);
  27.  
  28. static void     Handle_VIS_WANT_MIGHTSEE_DATA(VIS_WANT_MIGHTSEE_DATA* packet, NetvisSession* socket);
  29. static void     Handle_VIS_MIGHTSEE_DATA_NAK(VIS_MIGHTSEE_DATA_NAK* packet, NetvisSession* socket);
  30. static void     Handle_VIS_MIGHTSEE_DATA(VIS_MIGHTSEE_DATA* packet, NetvisSession* socket);
  31.  
  32. static void     Handle_VIS_LEAFTHREAD(VIS_LEAFTHREAD* packet, NetvisSession* socket);
  33. static void     Handle_VIS_LEAFTHREAD_ACK(VIS_LEAFTHREAD_ACK* packet, NetvisSession* socket);
  34. static void     Handle_VIS_LEAFTHREAD_NAK(VIS_LEAFTHREAD_NAK* packet, NetvisSession* socket);
  35.  
  36. static void     Handle_VIS_WANT_FULL_SYNC(WANT_FULL_SYNC* packet, NetvisSession* socket);
  37. static void     Handle_VIS_DONE_PORTAL(VIS_DONE_PORTAL* packet, NetvisSession* socket);
  38. static void     Handle_VIS_SYNC_PORTAL_CLUSTER(VIS_SYNC_PORTAL_CLUSTER* packet, NetvisSession* socket);
  39.  
  40. static void     Handle_VIS_GOING_DOWN(GOING_DOWN* packet, NetvisSession* socket);
  41.  
  42. void            basePacket::DroppedClientForPortalIndex(long clientid, long index)
  43. {
  44.     if (index < 0)
  45.         return;
  46.  
  47.     portal_t*       p = GetPortalPtr(index);
  48.  
  49.     hlassert(p);
  50.  
  51.     if (p->status == stat_working)
  52.     {
  53.         IfDebug(Developer(DEVELOPER_LEVEL_WARNING, "[#%d] Connection closed: portal %d reverted\n", clientid, index));
  54.         p->status = stat_none;
  55.     }
  56. }
  57.  
  58. INT             basePacket::getPacketSizeByType(INT type)
  59. {
  60.     switch ((PACKETtypes) type)
  61.     {
  62.     case VIS_PACKET_LOGIN:
  63.         return sizeof(VIS_LOGIN);
  64.     case VIS_PACKET_LOGIN_NAK:
  65.         return sizeof(VIS_LOGIN_NAK);
  66.     case VIS_PACKET_LOGIN_ACK:
  67.         return sizeof(VIS_LOGIN_ACK);
  68.  
  69.     case VIS_PACKET_WANT_BSP_DATA:
  70.         return sizeof(VIS_WANT_BSP_DATA);
  71.     case VIS_PACKET_BSP_DATA_NAK:
  72.         return sizeof(VIS_BSP_DATA_NAK);
  73.     case VIS_PACKET_BSP_DATA:
  74.         return VARIABLE_LENGTH_PACKET;
  75.     case VIS_PACKET_BSP_NAME:
  76.         return sizeof(VIS_BSP_NAME);
  77.  
  78.     case VIS_PACKET_WANT_PRT_DATA:
  79.         return sizeof(VIS_WANT_PRT_DATA);
  80.     case VIS_PACKET_PRT_DATA_NAK:
  81.         return sizeof(VIS_PRT_DATA_NAK);
  82.     case VIS_PACKET_PRT_DATA:
  83.         return VARIABLE_LENGTH_PACKET;
  84.  
  85.     case VIS_PACKET_WANT_MIGHTSEE_DATA:
  86.         return sizeof(VIS_WANT_MIGHTSEE_DATA);
  87.     case VIS_PACKET_MIGHTSEE_DATA_NAK:
  88.         return sizeof(VIS_MIGHTSEE_DATA_NAK);
  89.     case VIS_PACKET_MIGHTSEE_DATA:
  90.         return VARIABLE_LENGTH_PACKET;
  91.  
  92.     case VIS_PACKET_LEAFTHREAD:
  93.         return sizeof(VIS_LEAFTHREAD);
  94.     case VIS_PACKET_LEAFTHREAD_ACK:
  95.         return sizeof(VIS_LEAFTHREAD_ACK);
  96.     case VIS_PACKET_LEAFTHREAD_NAK:
  97.         return sizeof(VIS_LEAFTHREAD_NAK);
  98.  
  99.     case VIS_PACKET_WANT_FULL_SYNC:
  100.         return sizeof(WANT_FULL_SYNC);
  101.     case VIS_PACKET_DONE_PORTAL:                          // variable size in code, fixed size at runtime (depending on map data)
  102.         return myoffsetof(VIS_DONE_PORTAL, data) + g_bitbytes;
  103.     case VIS_PACKET_SYNC_PORTAL:
  104.         return myoffsetof(VIS_SYNC_PORTAL, data) + g_bitbytes;
  105.     case VIS_PACKET_SYNC_PORTAL_CLUSTER:
  106.         return VARIABLE_LENGTH_PACKET;
  107.  
  108.     case VIS_PACKET_GOING_DOWN:
  109.         return sizeof(GOING_DOWN);
  110.  
  111.     default:
  112.         return 0;
  113.     }
  114. }
  115.  
  116. void            basePacket::HandleIncomingPacket(basePacket* packet, NetvisSession* socket)
  117. {
  118.     switch (packet->getType())
  119.     {
  120.     case VIS_PACKET_LOGIN:
  121.         Handle_VIS_LOGIN((VIS_LOGIN*) packet, socket);
  122.         break;
  123.     case VIS_PACKET_LOGIN_NAK:
  124.         Handle_VIS_LOGIN_NAK((VIS_LOGIN_NAK*) packet, socket);
  125.         break;
  126.     case VIS_PACKET_LOGIN_ACK:
  127.         Handle_VIS_LOGIN_ACK((VIS_LOGIN_ACK*) packet, socket);
  128.         break;
  129.  
  130.     case VIS_PACKET_WANT_BSP_DATA:
  131.         Handle_VIS_WANT_BSP_DATA((VIS_WANT_BSP_DATA*) packet, socket);
  132.         break;
  133.     case VIS_PACKET_BSP_DATA_NAK:
  134.         Handle_VIS_BSP_DATA_NAK((VIS_BSP_DATA_NAK*) packet, socket);
  135.         break;
  136.     case VIS_PACKET_BSP_DATA:
  137.         Handle_VIS_BSP_DATA((VIS_BSP_DATA*) packet, socket);
  138.         break;
  139.     case VIS_PACKET_BSP_NAME:
  140.         Handle_VIS_BSP_NAME((VIS_BSP_NAME*) packet, socket);
  141.         break;
  142.  
  143.     case VIS_PACKET_WANT_PRT_DATA:
  144.         Handle_VIS_WANT_PRT_DATA((VIS_WANT_PRT_DATA*) packet, socket);
  145.         break;
  146.     case VIS_PACKET_PRT_DATA_NAK:
  147.         Handle_VIS_PRT_DATA_NAK((VIS_PRT_DATA_NAK*) packet, socket);
  148.         break;
  149.     case VIS_PACKET_PRT_DATA:
  150.         Handle_VIS_PRT_DATA((VIS_PRT_DATA*) packet, socket);
  151.         break;
  152.  
  153.     case VIS_PACKET_WANT_MIGHTSEE_DATA:
  154.         Handle_VIS_WANT_MIGHTSEE_DATA((VIS_WANT_MIGHTSEE_DATA*) packet, socket);
  155.         break;
  156.     case VIS_PACKET_MIGHTSEE_DATA_NAK:
  157.         Handle_VIS_MIGHTSEE_DATA_NAK((VIS_MIGHTSEE_DATA_NAK*) packet, socket);
  158.         break;
  159.     case VIS_PACKET_MIGHTSEE_DATA:
  160.         Handle_VIS_MIGHTSEE_DATA((VIS_MIGHTSEE_DATA*) packet, socket);
  161.         break;
  162.  
  163.     case VIS_PACKET_LEAFTHREAD:
  164.         Handle_VIS_LEAFTHREAD((VIS_LEAFTHREAD*) packet, socket);
  165.         break;
  166.     case VIS_PACKET_LEAFTHREAD_ACK:
  167.         Handle_VIS_LEAFTHREAD_ACK((VIS_LEAFTHREAD_ACK*) packet, socket);
  168.         break;
  169.     case VIS_PACKET_LEAFTHREAD_NAK:
  170.         Handle_VIS_LEAFTHREAD_NAK((VIS_LEAFTHREAD_NAK*) packet, socket);
  171.         break;
  172.  
  173.     case VIS_PACKET_WANT_FULL_SYNC:
  174.         Handle_VIS_WANT_FULL_SYNC((WANT_FULL_SYNC*) packet, socket);
  175.         break;
  176.     case VIS_PACKET_DONE_PORTAL:
  177.         Handle_VIS_DONE_PORTAL((VIS_DONE_PORTAL*) packet, socket);
  178.         break;
  179.     case VIS_PACKET_SYNC_PORTAL_CLUSTER:
  180.         Handle_VIS_SYNC_PORTAL_CLUSTER((VIS_SYNC_PORTAL_CLUSTER*) packet, socket);
  181.         break;
  182.  
  183.     case VIS_PACKET_GOING_DOWN:
  184.         Handle_VIS_GOING_DOWN((GOING_DOWN*) packet, socket);
  185.         break;
  186.     }
  187. }
  188.  
  189. void            Handle_VIS_GOING_DOWN(GOING_DOWN* packet, NetvisSession* socket)
  190. {
  191.     hlassert(packet->validate());
  192.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] receive GOING_DOWN\n", socket->m_ClientId));
  193.     Warning("[#%d] disconnected\n", socket->m_ClientId);
  194.  
  195.     if (g_vismode == VIS_MODE_SERVER)
  196.     {
  197.         socket->m_WorkQueueLock.EnterMutex();
  198.         NetvisSession::WorkQueue_i it = socket->m_WorkQueue.begin();
  199.         while (it != socket->m_WorkQueue.end())
  200.         {
  201.             packet->DroppedClientForPortalIndex(socket->m_ClientId, *it);
  202.             it++;
  203.         }
  204.         socket->m_WorkQueue.clear();
  205.         socket->m_WorkQueueLock.LeaveMutex();
  206.     }
  207.     else
  208.     {
  209.         socket->DisplayClientStats();
  210.         g_NetvisAbort = true;
  211.  
  212.         NetvisSleep(2000);
  213.         Error("Server dropped connection, exiting\n");
  214.     }
  215. }
  216.  
  217. void            Send_VIS_GOING_DOWN(NetvisSession* socket)
  218. {
  219.     GOING_DOWN      outpacket;
  220.  
  221.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "send GOING_DOWN\n"));
  222.     socket->SendPacket(&outpacket);
  223.     while (socket->m_PacketsCount)
  224.     {
  225.         NetvisSleep(2000);                                 // Wait long enough for server to receive our last few packets (if any)
  226.     }
  227. }
  228.  
  229. // Subroutine for Handle_VIS_WANT_FULL_SYNC
  230. static bool     Create_SYNC_PORTAL_OUTPACKET(VIS_SYNC_PORTAL* outpacket, int socketIndex, int globalIndex, int clientId)
  231. {
  232.     int             num = s_PortalArray[socketIndex];
  233.     portal_t*       tp = GetPortalPtr(num);
  234.  
  235.     if (tp)
  236.     {
  237.         if (tp->status == stat_done)
  238.         {
  239.             outpacket->setPortalIndex(num);
  240.             outpacket->setNumCanSee(tp->numcansee);
  241.             outpacket->setFromClient(tp->fromclient);
  242.             memcpy(outpacket->data, tp->visbits, g_bitbytes);
  243.  
  244.             IfDebug(Developer(DEVELOPER_LEVEL_MEGASPAM, "[#%d] send VIS_SYNC_PORTAL, portal = %d, socketIndex = %d, globalIndex = %d, size = %d\n", clientId, num, socketIndex, globalIndex, outpacket->getSize()));
  245.             return true;
  246.         }
  247.         else
  248.         {
  249.             IfDebug(Developer(DEVELOPER_LEVEL_ERROR, "[#%d] Handle_VIS_WANT_FULL_SYNC, portal = %d, socketIndex = %d, globalIndex = %d, s_PortalArray[socketIndex] = %d, portal not stat_done (stat was %d)\n", clientId, num, socketIndex, globalIndex, num, tp->status));
  250.         }
  251.     }
  252.     else
  253.     {
  254.         IfDebug(Developer(DEVELOPER_LEVEL_ERROR, "[#%d] GetPortalPtr() failed, returned NULL, portal = %d, socketIndex = %d, globalIndex = %d, s_PortalArray[socketIndex] = %d\n", clientId, num, socketIndex, globalIndex, num));
  255.     }
  256.     return false;
  257. }
  258.  
  259. void            Send_VIS_SYNC_PORTALs(NetvisSession* socket)
  260. {
  261.     s_PortalArrayLock.EnterMutex();
  262.     int             socketIndex = socket->m_SyncIndex;
  263.     int             globalIndex = g_PortalArrayIndex;
  264.     int             range = globalIndex - socketIndex;
  265.  
  266.     s_PortalArrayLock.LeaveMutex();
  267.     VIS_SYNC_PORTAL_CLUSTER outpacket;
  268.  
  269.     outpacket.setServerIndex(globalIndex);
  270.     if (range)
  271.     {
  272.         bool            done = false;
  273.  
  274.         socket->m_WorkDoneLock.EnterMutex();
  275.  
  276.         while (!done && (socketIndex < globalIndex))
  277.         {
  278.             if (socket->m_WorkDone.find(s_PortalArray[socketIndex]) == socket->m_WorkDone.end())        // Prevent reflection
  279.             {
  280.                 VIS_SYNC_PORTAL tmppacket;
  281.  
  282.                 if (Create_SYNC_PORTAL_OUTPACKET(&tmppacket, socketIndex, globalIndex, socket->m_ClientId))
  283.                 {
  284.                     if (outpacket.addSubpacket(&tmppacket))
  285.                     {
  286.                         socketIndex++;
  287.                     }
  288.                     else
  289.                     {
  290.                         done = true;
  291.                     }
  292.                 }
  293.                 else
  294.                 {
  295.                     done = true;                           // hit an error (probably portal has stat_done not set)
  296.                 }
  297.             }
  298.             else
  299.             {
  300.                 IfDebug(Developer(DEVELOPER_LEVEL_MEGASPAM, "Not sending SYNC_PORTAL packet of portal %d to client %d, client sent it to us!\n", s_PortalArray[socketIndex], socket->m_ClientId));
  301.                 socketIndex++;
  302.             }
  303.         }
  304.  
  305.         socket->m_WorkDoneLock.LeaveMutex();
  306.  
  307.         if (socketIndex < globalIndex)
  308.         {
  309.             outpacket.setMoreToSync(1);
  310.         }
  311.         else
  312.         {
  313.             outpacket.setMoreToSync(0);
  314.         }
  315.         int             workindex = 0;
  316.  
  317.         socket->m_WorkQueueLock.EnterMutex();
  318.         while (socket->m_WorkQueue.size() < WORK_QUEUE_SIZE)
  319.         {
  320.             long            work = GetNextPortalIndex();
  321.  
  322.             socket->m_WorkQueue.push_back(work);
  323.             outpacket.setWork(work, workindex);
  324.             workindex++;
  325.             IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] Adding work %d to SYNC_PORTAL_CLUSTER\n", socket->m_ClientId, work));
  326.         }
  327.         socket->m_WorkQueueLock.LeaveMutex();
  328.         // Remaining index[] should still be set to -1 from the constructor
  329.         IfDebug(Developer(DEVELOPER_LEVEL_FLUFF,
  330.                   "[#%d] Sending SYNC_PORTAL_CLUSTER with %d subpackets, %d work jobs, more_to_sync(%d)\n",
  331.                   socket->m_ClientId, socketIndex - socket->m_SyncIndex, workindex, outpacket.getMoreToSync())); // TODO print all work sent
  332.  
  333.         socket->SendPacket(&outpacket);
  334.         socket->m_SyncIndex = socketIndex;
  335.     }
  336.     else                                                   // Just more work
  337.     {
  338.         outpacket.setMoreToSync(0);
  339.         int             workindex = 0;
  340.  
  341.         socket->m_WorkQueueLock.EnterMutex();
  342.         while (socket->m_WorkQueue.size() < WORK_QUEUE_SIZE)
  343.         {
  344.             long            work = GetNextPortalIndex();
  345.  
  346.             socket->m_WorkQueue.push_back(work);
  347.             outpacket.setWork(work, workindex);
  348.             workindex++;
  349.             IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] Adding work %d to SYNC_PORTAL_CLUSTER\n", socket->m_ClientId, work));
  350.         }
  351.         socket->m_WorkQueueLock.LeaveMutex();
  352.         // Remaining index[] should still be set to -1 from the constructor
  353.         IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] Sending SYNC_PORTAL_CLUSTER with %d work jobs\n", socket->m_ClientId,
  354.                   workindex));
  355.         socket->SendPacket(&outpacket);
  356.     }
  357. }
  358.  
  359. void            Handle_VIS_WANT_FULL_SYNC(WANT_FULL_SYNC* packet, NetvisSession* socket)
  360. {
  361.     hlassert(packet->validate());
  362.     hlassert(g_vismode == VIS_MODE_SERVER);
  363.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] receive WANT_FULL_SYNC\n", socket->m_ClientId));
  364.  
  365.     Send_VIS_SYNC_PORTALs(socket);
  366. }
  367.  
  368. void            Send_VIS_WANT_FULL_SYNC_ping(void)
  369. {
  370.     if (!s_OutstandingSyncRequests)
  371.     {
  372.         Send_VIS_WANT_FULL_SYNC();
  373.     }
  374.     else
  375.     {
  376.         IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "Send_VIS_WANT_FULL_SYNC_ping skipped (outstanding:%d)\n",
  377.                   (int)s_OutstandingSyncRequests));
  378.     }
  379. }
  380.  
  381. void            Send_VIS_WANT_FULL_SYNC(void)
  382. {
  383.     WANT_FULL_SYNC  outpacket;
  384.  
  385.     s_OutstandingSyncRequests++;
  386.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "send WANT_FULL_SYNC (outstanding:%d)\n", (int)s_OutstandingSyncRequests));
  387.     g_ClientSession->SendPacket(&outpacket);
  388. }
  389.  
  390. void            Flag_VIS_DONE_PORTAL(long portalindex)
  391. {
  392.     s_PortalArrayLock.EnterMutex();
  393.     hlassert(g_PortalArrayIndex < PORTAL_ARRAY_MAX_SIZE);
  394.     s_PortalArray[g_PortalArrayIndex] = portalindex;
  395.     g_PortalArrayIndex++;
  396.     s_PortalArrayLock.LeaveMutex();
  397. }
  398.  
  399. void            Handle_VIS_DONE_PORTAL(VIS_DONE_PORTAL* packet, NetvisSession* socket)
  400. {
  401.     hlassert(packet->validate());
  402.     hlassert(g_vismode == VIS_MODE_SERVER);
  403.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] receive VIS_DONE_PORTAL, index = %d\n", socket->m_ClientId, packet->getPortalIndex()));
  404.  
  405.     portal_t*       p = GetPortalPtr(packet->getPortalIndex());
  406.  
  407.     hlassert(p);
  408.     hlassert(p->status == stat_working);
  409.     if (p->status == stat_done)
  410.     {
  411.         IfDebug(Developer(DEVELOPER_LEVEL_WARNING, "[#%d] WARNING: portal %d already evaluated by client (%d)\n",
  412.                   socket->m_ClientId, packet->getPortalIndex(), p->fromclient));
  413.         Send_VIS_SYNC_PORTALs(socket);                     // SYNC_PORTALs packet can now assign work (must always respond or count gets off)
  414.         return;
  415.     }
  416.  
  417.     p->numcansee = packet->getNumCanSee();
  418.     p->visbits = (byte*) malloc(g_bitbytes);
  419.     memcpy(p->visbits, packet->data, g_bitbytes);
  420.     p->fromclient = socket->m_ClientId;
  421.     p->status = stat_done;
  422.  
  423.     s_PortalArrayLock.EnterMutex();
  424.  
  425.     hlassert(g_PortalArrayIndex < PORTAL_ARRAY_MAX_SIZE);
  426.     s_PortalArray[g_PortalArrayIndex] = packet->getPortalIndex();
  427.     socket->m_WorkDoneLock.EnterMutex();
  428.     socket->m_WorkDone.insert(packet->getPortalIndex());
  429.     socket->m_WorkDoneLock.LeaveMutex();
  430.     socket->m_PortalCount++;
  431.     g_PortalArrayIndex++;
  432.  
  433.     s_PortalArrayLock.LeaveMutex();
  434.  
  435.     socket->m_WorkQueueLock.EnterMutex();
  436. #ifdef _DEBUG
  437.     int             queue_front_val = socket->m_WorkQueue.front();
  438.     int             current_index = packet->getPortalIndex();
  439.  
  440.     hlassert(queue_front_val == current_index);            // Should alwasy be in FIFO order on client and server both, should never deviate
  441. #endif
  442.     socket->m_WorkQueue.pop_front();
  443.     socket->m_WorkQueueLock.LeaveMutex();
  444.  
  445.     Send_VIS_SYNC_PORTALs(socket);                         // SYNC_PORTALs packet can now assign work
  446. }
  447.  
  448. void            Send_VIS_DONE_PORTAL(long portalindex, portal_t* p)
  449. {
  450.     hlassert(g_vismode == VIS_MODE_CLIENT);
  451.  
  452.     VIS_DONE_PORTAL outpacket;
  453.  
  454.     hlassert(g_bitbytes <= sizeof(outpacket.data));
  455.  
  456.     outpacket.setPortalIndex(portalindex);
  457.     outpacket.setNumCanSee(p->numcansee);
  458.     memcpy(outpacket.data, p->visbits, g_bitbytes);
  459.  
  460.     g_visportalindex = WAITING_FOR_PORTAL_INDEX;
  461.     g_ClientSession->m_PortalCount++;
  462.     s_OutstandingSyncRequests++;
  463.  
  464.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "send VIS_DONE_PORTAL (outstanding:%d), index = %d, size = %d\n",
  465.               (int)s_OutstandingSyncRequests, outpacket.getPortalIndex(), outpacket.getSize()));
  466.     g_ClientSession->SendPacket(&outpacket);
  467. }
  468.  
  469. void            Handle_VIS_SYNC_PORTAL_CLUSTER(VIS_SYNC_PORTAL_CLUSTER* packet, NetvisSession* socket)
  470. {
  471.     hlassert(packet->validate());
  472.     hlassert(g_vismode == VIS_MODE_CLIENT);
  473.     s_OutstandingSyncRequests--;
  474.     s_IdleCounter++;
  475.  
  476.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "Received VIS_SYNC_PORTAL_CLUSTER (outstanding:%d), count = %d\n", (int)s_OutstandingSyncRequests, packet->getSubpacketCount()));
  477.  
  478.     g_serverindex = packet->getServerIndex();
  479.     int             count = packet->getSubpacketCount();            // Can be zero, if fully synced but server is just sending us work
  480.  
  481.     //    hlassert(count); 
  482.     for (int i = 0; i < count; i++)
  483.     {
  484.         VIS_SYNC_PORTAL* subpacket = packet->getSubpacket(i);
  485.  
  486.         hlassert(subpacket);
  487.         hlassert(subpacket->validate());
  488.         portal_t*       p = GetPortalPtr(subpacket->getPortalIndex());
  489.  
  490.         hlassert(p);
  491.  
  492.         IfDebug(Developer(DEVELOPER_LEVEL_MEGASPAM, "Received SYNC_PORTAL subpacket #%d, portal = %d, fromclient = %d\n", i, subpacket->getPortalIndex(), subpacket->getFromClient()));
  493.  
  494.         if (p->status == stat_none)
  495.         {
  496.             p->numcansee = subpacket->getNumCanSee();
  497.             p->visbits = (byte*) malloc(g_bitbytes);
  498.             memcpy(p->visbits, subpacket->data, g_bitbytes);
  499.             p->fromclient = subpacket->getFromClient();
  500.             p->status = stat_done;
  501.         }
  502.         else if (subpacket->getFromClient() != p->fromclient)
  503.         {
  504.             const char*     match;
  505.             developer_level_t level;
  506.  
  507.             if (p->visbits)
  508.             {
  509.                 if (memcmp(p->visbits, &subpacket->data[0], g_bitbytes))
  510.                 {
  511.                     match = "different";
  512.                     level = DEVELOPER_LEVEL_ERROR;
  513.                 }
  514.                 else
  515.                 {
  516.                     match = "identical";
  517.                     level = DEVELOPER_LEVEL_WARNING;
  518.                 }
  519.             }
  520.             else
  521.             {
  522.                 match = "unexpected";
  523.                 level = DEVELOPER_LEVEL_ERROR;
  524.             }
  525.             IfDebug(Developer(level,
  526.                       "Received %s SYNC_PORTAL packet for a portal(%d) originating from client (%d) which was already processed by client (%d)\n",
  527.                       match, subpacket->getPortalIndex(), subpacket->getFromClient(), p->fromclient));
  528.         }
  529.     }
  530.     for (int j = 0; j < WORK_QUEUE_SIZE; j++)
  531.     {
  532.         INT32           work = packet->getWork(j);
  533.  
  534.         if ((work >= 0) || (work == NO_PORTAL_INDEX))
  535.         {
  536.             IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "VIS_SYNC_PORTAL_CLUSTER, added work %d to queue\n", work));
  537.             addWorkToClientQueue(work);
  538.         }
  539.     }
  540.     if (packet->getMoreToSync() > 0)
  541.     {
  542.         Send_VIS_WANT_FULL_SYNC();
  543.     }
  544. }
  545.  
  546. void            Send_VIS_LOGIN(void)
  547. {
  548.     VIS_LOGIN       outpacket;
  549.  
  550.     gethostname(outpacket.hostname, sizeof(outpacket.hostname));
  551.  
  552.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "send VIS_LOGIN\n"));
  553.     g_ClientSession->SendPacket(&outpacket);
  554. }
  555.  
  556. void            Handle_VIS_LOGIN(VIS_LOGIN* packet, NetvisSession* socket)
  557. {
  558.     hlassert(packet->validate());
  559.     hlassert(g_vismode == VIS_MODE_SERVER);
  560.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] receive VIS_LOGIN (version %u)\n", socket->m_ClientId, packet->getProtocolVersion()));
  561.     if (packet->getProtocolVersion() == NETVIS_PROTOCOL_VERSION)
  562.     {
  563.         VIS_LOGIN_ACK   outpacket;
  564.  
  565.         socket->m_RemoteHostname = packet->hostname;
  566.         int             ClientId = ++g_nextclientid;
  567.  
  568.         outpacket.setClientId(ClientId);
  569.         outpacket.setFullvis(g_fullvis);
  570.         socket->m_ClientId = ClientId;
  571.         IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] send VIS_LOGIN_ACK\n", socket->m_ClientId));
  572.         socket->SendPacket(&outpacket);
  573.     }
  574.     else
  575.     {
  576.         VIS_LOGIN_NAK   outpacket;
  577.  
  578.         IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] send VIS_LOGIN_NAK\n", socket->m_ClientId));
  579.         socket->SendPacket(&outpacket);
  580.     }
  581. }
  582.  
  583. void            Handle_VIS_LOGIN_NAK(VIS_LOGIN_NAK* packet, NetvisSession* socket)
  584. {
  585.     hlassert(packet->validate());
  586.     hlassert(g_vismode == VIS_MODE_CLIENT);
  587.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] receive VIS_LOGIN_ACK\n", socket->m_ClientId));
  588.     g_NetvisAbort = true;
  589.     Error("Incompatible netvis version on server, server is version %u, client is %u\n", packet->getProtocolVersion(), NETVIS_PROTOCOL_VERSION);
  590. }
  591.  
  592. void            Handle_VIS_LOGIN_ACK(VIS_LOGIN_ACK* packet, NetvisSession* socket)
  593. {
  594.     hlassert(packet->validate());
  595.     hlassert(g_vismode == VIS_MODE_CLIENT);
  596.     socket->m_ClientId = g_clientid = packet->getClientId();
  597.     g_fullvis = packet->getFullvis();
  598.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] receive VIS_LOGIN_ACK\n", socket->m_ClientId));
  599. }
  600.  
  601. //
  602. // .BSP Download request/handling functions
  603. //
  604. static unsigned s_bsp_image_bytes_written = 0;
  605. static char*    s_bsp_compressed_image = NULL;
  606.  
  607. void            Send_VIS_WANT_BSP_DATA(void)
  608. {
  609.     hlassert(g_vismode == VIS_MODE_CLIENT);
  610.     VIS_WANT_BSP_DATA outpacket;
  611.  
  612.     s_bsp_image_bytes_written = 0;
  613.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "send VIS_WANT_BSP_DATA\n"));
  614.     g_ClientSession->SendPacket(&outpacket);
  615. }
  616.  
  617. static void     Send_VIS_BSP_DATA(NetvisSession* socket)
  618. {
  619.     hlassert(g_bsp_image);
  620.     hlassert(g_bsp_size);
  621.     hlassert(g_bsp_compressed_size);
  622.     const unsigned  chunk_size = sizeofElement(VIS_BSP_DATA, data);
  623.     unsigned        chunks = g_bsp_compressed_size / chunk_size;
  624.     unsigned        remainder = g_bsp_compressed_size % chunk_size;
  625.  
  626.     hlassert(chunks || remainder);
  627.  
  628.     unsigned        x;
  629.     unsigned        offset;
  630.     VIS_BSP_DATA    outpacket;
  631.  
  632.     outpacket.setCompressedSize(g_bsp_compressed_size);
  633.     outpacket.setUncompressedSize(g_bsp_size);
  634.     outpacket.setFragmentSize(chunk_size);
  635.     for (x = 0, offset = 0; x < chunks; x++, offset += chunk_size)
  636.     {
  637.         outpacket.setOffset(offset);
  638.         memcpy(outpacket.data, g_bsp_image + offset, chunk_size);
  639.         IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] send VIS_BSP_DATA (fragment %u of %u)\n", socket->m_ClientId, x + 1,
  640.                   chunks));
  641.         socket->SendPacket(&outpacket);
  642.     }
  643.     if (remainder)
  644.     {
  645.         outpacket.setOffset(offset);
  646.         outpacket.setFragmentSize(remainder);
  647.         memcpy(outpacket.data, g_bsp_image + offset, remainder);
  648.         IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] send VIS_BSP_DATA (fragment %u of %u) (remainder size %u) \n",
  649.                   socket->m_ClientId, x + 1, chunks, remainder));
  650.         socket->SendPacket(&outpacket);
  651.     }
  652. }
  653.  
  654. void            Handle_VIS_WANT_BSP_DATA(VIS_WANT_BSP_DATA* packet, NetvisSession* socket)
  655. {
  656.     hlassert(packet->validate());
  657.     hlassert(g_vismode == VIS_MODE_SERVER);
  658.     if (g_bsp_image)
  659.     {
  660.         VIS_BSP_NAME outpacket(g_Mapname);
  661.         socket->SendPacket(&outpacket);
  662.  
  663.         Send_VIS_BSP_DATA(socket);
  664.     }
  665.     else
  666.     {
  667.         VIS_BSP_DATA_NAK outpacket;
  668.  
  669.         IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] send VIS_BSP_DATA_NAK\n", socket->m_ClientId));
  670.         socket->SendPacket(&outpacket);
  671.     }
  672. }
  673.  
  674. void            Handle_VIS_BSP_DATA(VIS_BSP_DATA* packet, NetvisSession* socket)
  675. {
  676.     hlassert(packet->validate());
  677.     hlassert(packet->myValidate());
  678.     hlassert(g_vismode == VIS_MODE_CLIENT);
  679.     hlassert(s_bsp_image_bytes_written + packet->getFragmentSize() <= packet->getCompressedSize());
  680.  
  681.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] received BSP data fragment (compressedsize %u, uncompressedsize %u, fragmentsize %u, offset %u)\n",
  682.               socket->m_ClientId, packet->getCompressedSize(), packet->getUncompressedSize(), packet->getFragmentSize(), packet->getOffset()));
  683.  
  684.     if (s_bsp_compressed_image)
  685.     {
  686.         memcpy(s_bsp_compressed_image + packet->getOffset(), packet->data, packet->getFragmentSize());
  687.         s_bsp_image_bytes_written += packet->getFragmentSize();
  688.     }
  689.     else
  690.     {
  691.         s_bsp_compressed_image = (char*)calloc(1, packet->getCompressedSize());
  692.         memcpy(s_bsp_compressed_image + packet->getOffset(), packet->data, packet->getFragmentSize());
  693.         s_bsp_image_bytes_written += packet->getFragmentSize();
  694.     }
  695.  
  696.     if (s_bsp_image_bytes_written == packet->getCompressedSize())
  697.     {
  698.         unsigned long compressed_size = packet->getCompressedSize();
  699.         unsigned long uncompressed_size = packet->getUncompressedSize();
  700.         g_bsp_image = (char*)calloc(1, uncompressed_size);
  701.     
  702.         if (uncompress((byte*)g_bsp_image, &uncompressed_size, (byte*)s_bsp_compressed_image, compressed_size) != Z_OK)
  703.         {
  704.             Send_VIS_GOING_DOWN(socket);
  705.             Error("zlib Uncompress error with bsp image\n");
  706.         }
  707.  
  708.         free(s_bsp_compressed_image);
  709.         s_bsp_compressed_image = NULL;
  710.         g_bsp_downloaded = true;
  711.     }
  712. }
  713.  
  714. void            Handle_VIS_BSP_DATA_NAK(VIS_BSP_DATA_NAK* packet, NetvisSession* socket)
  715. {
  716.     hlassert(packet->validate());
  717.     hlassert(g_vismode == VIS_MODE_CLIENT);
  718.  
  719.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] receive VIS_BSP_DATA_NAK\n", socket->m_ClientId));
  720.  
  721.     Log("Waiting for bsp image, retrying after 5 seconds . . .\n");
  722.     NetvisSleep(5000);                                     // Repeatedly try to get BSP data image
  723.     Send_VIS_WANT_BSP_DATA();
  724. }
  725.  
  726. void            Handle_VIS_BSP_NAME(VIS_BSP_NAME* packet, NetvisSession* socket)
  727. {
  728.     hlassert(packet->validate());
  729.     hlassert(g_vismode == VIS_MODE_CLIENT);
  730.  
  731.     safe_strncpy(g_Mapname, packet->getName(), _MAX_PATH);
  732.     Log("Processing map '%s'\n", g_Mapname);
  733. }
  734.  
  735. //
  736. // .PRT Download request/handling functions
  737. //
  738. static unsigned s_prt_image_bytes_written = 0;
  739. static char*    s_prt_compressed_image = NULL;
  740.  
  741. void            Send_VIS_WANT_PRT_DATA(void)
  742. {
  743.     hlassert(g_vismode == VIS_MODE_CLIENT);
  744.     s_prt_image_bytes_written = 0;
  745.     VIS_WANT_PRT_DATA outpacket;
  746.  
  747.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "send VIS_WANT_PRT_DATA\n"));
  748.     g_ClientSession->SendPacket(&outpacket);
  749. }
  750.  
  751. static void     Send_VIS_PRT_DATA(NetvisSession* socket)
  752. {
  753.     hlassert(g_prt_image);
  754.     hlassert(g_prt_size);
  755.     const unsigned  chunk_size = sizeofElement(VIS_PRT_DATA, data);
  756.     unsigned        chunks = g_prt_compressed_size / chunk_size;
  757.     unsigned        remainder = g_prt_compressed_size % chunk_size;
  758.  
  759.     hlassert(chunks || remainder);
  760.  
  761.     unsigned        x;
  762.     unsigned        offset;
  763.     VIS_PRT_DATA    outpacket;
  764.  
  765.     outpacket.setCompressedSize(g_prt_compressed_size);
  766.     outpacket.setUncompressedSize(g_prt_size);
  767.     outpacket.setFragmentSize(chunk_size);
  768.     for (x = 0, offset = 0; x < chunks; x++, offset += chunk_size)
  769.     {
  770.         outpacket.setOffset(offset);
  771.         memcpy(outpacket.data, g_prt_image + offset, chunk_size);
  772.         IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] send VIS_PRT_DATA (fragment %u of %u)\n", socket->m_ClientId, x + 1, chunks));
  773.         socket->SendPacket(&outpacket);
  774.     }
  775.     if (remainder)
  776.     {
  777.         outpacket.setOffset(offset);
  778.         outpacket.setFragmentSize(remainder);
  779.         memcpy(outpacket.data, g_prt_image + offset, remainder);
  780.         IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] send VIS_PRT_DATA (fragment %u of %u) (remainder size %u) \n", socket->m_ClientId, x + 1, chunks, remainder));
  781.         socket->SendPacket(&outpacket);
  782.     }
  783. }
  784.  
  785. void            Handle_VIS_WANT_PRT_DATA(VIS_WANT_PRT_DATA* packet, NetvisSession* socket)
  786. {
  787.     hlassert(packet->validate());
  788.     hlassert(g_vismode == VIS_MODE_SERVER);
  789.  
  790.     if (g_prt_image)
  791.     {
  792.         Send_VIS_PRT_DATA(socket);
  793.     }
  794.     else
  795.     {
  796.         VIS_PRT_DATA_NAK outpacket;
  797.  
  798.         IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] send VIS_PRT_DATA_NAK\n", socket->m_ClientId));
  799.         socket->SendPacket(&outpacket);
  800.     }
  801. }
  802.  
  803. void            Handle_VIS_PRT_DATA(VIS_PRT_DATA* packet, NetvisSession* socket)
  804. {
  805.     hlassert(packet->validate());
  806.     hlassert(packet->myValidate());
  807.     hlassert(g_vismode == VIS_MODE_CLIENT);
  808.     hlassert(s_prt_image_bytes_written + packet->getFragmentSize() <= packet->getCompressedSize());
  809.  
  810.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] received PRT data fragment (compressedsize %u, uncompressedsize %u, fragmentsize %u, offset %u)\n",
  811.               socket->m_ClientId, packet->getCompressedSize(), packet->getUncompressedSize(), packet->getFragmentSize(), packet->getOffset()));
  812.  
  813.     if (s_prt_compressed_image)
  814.     {
  815.         memcpy(s_prt_compressed_image + packet->getOffset(), packet->data, packet->getFragmentSize());
  816.         s_prt_image_bytes_written += packet->getFragmentSize();
  817.     }
  818.     else
  819.     {
  820.         s_prt_compressed_image = (char*)calloc(1, packet->getCompressedSize());
  821.         memcpy(s_prt_compressed_image + packet->getOffset(), packet->data, packet->getFragmentSize());
  822.         s_prt_image_bytes_written += packet->getFragmentSize();
  823.     }
  824.  
  825.     if (s_prt_image_bytes_written == packet->getCompressedSize())
  826.     {
  827.         unsigned long compressed_size = packet->getCompressedSize();
  828.         unsigned long uncompressed_size = packet->getUncompressedSize();
  829.         g_prt_image = (char*)calloc(1, uncompressed_size);
  830.     
  831.         if (uncompress((byte*)g_prt_image, &uncompressed_size, (byte*)s_prt_compressed_image, compressed_size) != Z_OK)
  832.         {
  833.             Send_VIS_GOING_DOWN(socket);
  834.             Error("zlib Uncompress error with prt image\n");
  835.         }
  836.  
  837.         free(s_prt_compressed_image);
  838.         s_prt_compressed_image = NULL;
  839.         g_prt_downloaded = true;
  840.     }
  841. }
  842.  
  843. void            Handle_VIS_PRT_DATA_NAK(VIS_PRT_DATA_NAK* packet, NetvisSession* socket)
  844. {
  845.     hlassert(packet->validate());
  846.     hlassert(g_vismode == VIS_MODE_CLIENT);
  847.  
  848.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] receive VIS_PRT_DATA_NAK\n", socket->m_ClientId));
  849.  
  850.     Log("Waiting for prt image, retrying after 5 seconds . . .\n");
  851.     NetvisSleep(5000);                                     // Repeatedly try to get PRT data image
  852.     Send_VIS_WANT_PRT_DATA();
  853. }
  854.  
  855. //
  856. // BasePortalVis download
  857. //
  858.  
  859. void            Send_VIS_WANT_MIGHTSEE_DATA(void)
  860. {
  861.     VIS_WANT_MIGHTSEE_DATA outpacket;
  862.  
  863.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "send VIS_WANT_MIGHTSEE_DATA\n"));
  864.     g_ClientSession->SendPacket(&outpacket);
  865. }
  866.  
  867. static void     Send_VIS_MIGHTSEE_DATA(NetvisSession* socket)
  868. {
  869.  
  870.     unsigned x;
  871.     const unsigned numportals = g_numportals * 2;
  872.     portal_t* p = g_portals;
  873.  
  874.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] send VIS_MIGHTSEE_DATA (%u bytes)\n", socket->m_ClientId, g_bitbytes * numportals));
  875.  
  876.     for (x=0; x<numportals; x++, p++)
  877.     {
  878.         VIS_MIGHTSEE_DATA outpacket;
  879.         outpacket.setPortalIndex(x);
  880.         outpacket.setNumMightSee(p->nummightsee);
  881.         memcpy(outpacket.data, p->mightsee, g_bitbytes);
  882.         socket->SendPacket(&outpacket);
  883.     }
  884. }
  885.  
  886. void            Handle_VIS_WANT_MIGHTSEE_DATA(VIS_WANT_MIGHTSEE_DATA* packet, NetvisSession* socket)
  887. {
  888.     hlassert(packet->validate());
  889.     hlassert(g_vismode == VIS_MODE_SERVER);
  890.  
  891.     if (g_visstate <= VIS_BASE_PORTAL_VIS)
  892.     {
  893.         VIS_MIGHTSEE_DATA_NAK outpacket;
  894.         socket->SendPacket(&outpacket);
  895.     }
  896.     else if (g_visstate <= VIS_POST)
  897.     {
  898.         Send_VIS_MIGHTSEE_DATA(socket);
  899.     }
  900.     else
  901.     {
  902.         Send_VIS_GOING_DOWN(socket);
  903.     }
  904. }
  905.  
  906. void            Handle_VIS_MIGHTSEE_DATA_NAK(VIS_MIGHTSEE_DATA_NAK* packet, NetvisSession* socket)
  907. {
  908.     hlassert(packet->validate());
  909.     hlassert(g_vismode == VIS_MODE_CLIENT);
  910.  
  911.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] receive VIS_MIGHTSEE_DATA_NAK\n", socket->m_ClientId));
  912.  
  913.     Log("Waiting for BasePortalVis data from server, retrying after 5 seconds . . .\n");
  914.     NetvisSleep(5000);                                     // Repeatedly try to get PRT data image
  915.     Send_VIS_WANT_MIGHTSEE_DATA();
  916. }
  917.  
  918. void            Handle_VIS_MIGHTSEE_DATA(VIS_MIGHTSEE_DATA* packet, NetvisSession* socket)
  919. {
  920.     hlassert(packet->validate());
  921.     hlassert(g_vismode == VIS_MODE_CLIENT);
  922.  
  923.     INT32 index = packet->getPortalIndex();
  924.     IfDebug(Developer(DEVELOPER_LEVEL_MEGASPAM, "[#%d] receive VIS_MIGHTSEE_DATA (%d)\n", socket->m_ClientId, index));
  925.  
  926.     portal_t*       p = GetPortalPtr(index);
  927.     hlassert(p);
  928.     hlassert(p->mightsee == NULL);
  929.  
  930.     p->nummightsee = packet->getNumMightSee();
  931.     p->mightsee = (byte*) malloc(g_bitbytes);
  932.     memcpy(p->mightsee , packet->data, g_bitbytes);
  933.  
  934.     index++;    // Fix fencepost comparison
  935.     if (index == (g_numportals * 2))
  936.     {
  937.         IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] mightsee data download complete (%d)\n", socket->m_ClientId));
  938.         g_mightsee_downloaded = true;
  939.     }
  940. }
  941.  
  942. //
  943. // Leafthread commmencement (client needs work) request
  944. //
  945.  
  946. void            Send_VIS_LEAFTHREAD(long portalleafs, long numportals, long bitbytes)
  947. {
  948.     VIS_LEAFTHREAD  packet;
  949.  
  950.     packet.setPortalLeafs(portalleafs);
  951.     packet.setNumPortals(numportals);
  952.     packet.setBitBytes(bitbytes);
  953.  
  954.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "send VIS_LEAFTHREAD\n"));
  955.     g_ClientSession->SendPacket(&packet);
  956. }
  957.  
  958. void            Handle_VIS_LEAFTHREAD(VIS_LEAFTHREAD* packet, NetvisSession* socket)
  959. {
  960.     hlassert(packet->validate());
  961.     hlassert(g_vismode == VIS_MODE_SERVER);
  962.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] receive VIS_LEAFTHREAD\n", socket->m_ClientId));
  963.  
  964.     long            visleafs = g_visleafs;                 // Prevent if() from reading zero and being written to afterwards (during output of packet and messages)
  965.     long            visportals = g_visportals;             // same
  966.     long            bitbytes = g_bitbytes;
  967.  
  968.     if ((packet->getPortalLeafs() == visleafs) && (packet->getNumPortals() == visportals)
  969.         && (packet->getBitBytes() == bitbytes))
  970.     {
  971.         VIS_LEAFTHREAD_ACK outpacket;
  972.  
  973.         IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] send VIS_LEAFTHREAD_ACK\n", socket->m_ClientId));
  974.         Log("Client #%d beginning work\n", socket->m_ClientId);
  975.         socket->SendPacket(&outpacket);
  976.     }
  977.     else
  978.     {
  979.         IfDebug(Developer(DEVELOPER_LEVEL_SPAM,
  980.                   "[#%d] Client/Server portal mismatch : client portals(%d) leafs (%d) bitbytes (%d), server portals(%d) leafs(%d) bitbytes (%d)\n",
  981.                   socket->m_ClientId, visportals, visleafs, bitbytes, packet->getNumPortals(), packet->getPortalLeafs(),
  982.                   packet->getBitBytes()));
  983.         VIS_LEAFTHREAD_NAK outpacket;
  984.  
  985.         outpacket.setPortalLeafs(visleafs);
  986.         outpacket.setNumPortals(visportals);
  987.         outpacket.setBitBytes(bitbytes);
  988.         IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] send VIS_LEAFTHREAD_NAK\n", socket->m_ClientId));
  989.         socket->SendPacket(&outpacket);
  990.     }
  991. }
  992.  
  993. void            Handle_VIS_LEAFTHREAD_ACK(VIS_LEAFTHREAD_ACK* packet, NetvisSession* socket)
  994. {
  995.     hlassert(packet->validate());
  996.     hlassert(g_vismode == VIS_MODE_CLIENT);
  997.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] receive VIS_LEAFTHREAD_ACK\n", socket->m_ClientId));
  998.  
  999.     g_visleafthread = 1;
  1000. }
  1001.  
  1002. void            Handle_VIS_LEAFTHREAD_NAK(VIS_LEAFTHREAD_NAK* packet, NetvisSession* socket)
  1003. {
  1004.     hlassert(packet->validate());
  1005.     hlassert(g_vismode == VIS_MODE_CLIENT);
  1006.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "[#%d] receive VIS_LEAFTHREAD_NAK\n", socket->m_ClientId));
  1007.  
  1008.     g_visleafthread = 0;
  1009.  
  1010.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM,
  1011.               "[#%d] Client/Server portal mismatch : client portals(%d) leafs (%d) bitbytes(%d), server portals(%d) leafs(%d) bitbytes(%d)\n",
  1012.               socket->m_ClientId, packet->getNumPortals(), packet->getPortalLeafs(), packet->getBitBytes(),
  1013.               g_visportals, g_visleafs, g_bitbytes));
  1014.     if ((packet->getNumPortals() == 0) || (packet->getPortalLeafs() == 0) || (packet->getBitBytes() == 0))
  1015.     {
  1016.         // Client finished BasePortalVis before server, try again periodically
  1017.         NetvisSleep(5000);                                 // Repeatedly try LEAFTHREAD start every 5 seconds
  1018.         Send_VIS_LEAFTHREAD(g_visleafs, g_visportals, g_bitbytes);
  1019.     }
  1020.     else
  1021.     {
  1022.         Send_VIS_GOING_DOWN(socket);
  1023.     }
  1024. }
  1025.  
  1026. //
  1027. // Work queue functions
  1028. //
  1029.  
  1030. static          std::deque < long >s_ClientWorkQueue;
  1031. static Mutex    s_ClientWorkQueueLock;                     // protects s_ClientWorkQueue
  1032. static ReferenceCounter s_OutOfWorkFlag;
  1033.  
  1034. int             outOfWork(void)
  1035. {
  1036.     s_IdleCounter = 0;
  1037.     s_ClientWorkQueueLock.EnterMutex();
  1038.     s_OutOfWorkFlag = s_ClientWorkQueue.size();
  1039.     s_ClientWorkQueueLock.LeaveMutex();
  1040.     return (s_OutOfWorkFlag == 0);
  1041. }
  1042.  
  1043. int             stillOutOfWork(void)
  1044. {
  1045.     return (s_OutOfWorkFlag == 0);
  1046. }
  1047.  
  1048. int             needServerUpdate(void)
  1049. {
  1050.     return (s_IdleCounter == 0);
  1051. }
  1052.  
  1053. void            addWorkToClientQueue(long index)
  1054. {
  1055.     s_ClientWorkQueueLock.EnterMutex();                    // already locked from Handle_VIS_ code
  1056.     s_ClientWorkQueue.push_back(index);
  1057.     s_OutOfWorkFlag++;
  1058.     s_ClientWorkQueueLock.LeaveMutex();
  1059.     IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "addWorkToClientQueue(%d)\n", index));
  1060. }
  1061.  
  1062. long            getWorkFromClientQueue(void)
  1063. {
  1064.     s_ClientWorkQueueLock.EnterMutex();
  1065.     if (s_ClientWorkQueue.empty())
  1066.     {
  1067.         g_visportalindex = WAITING_FOR_PORTAL_INDEX;
  1068.         IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "getWorkFromClientQueue returning WAITING_FOR_PORTAL_INDEX\n"));
  1069.     }
  1070.     else
  1071.     {
  1072.         g_visportalindex = s_ClientWorkQueue.front();
  1073.         s_ClientWorkQueue.pop_front();
  1074.         IfDebug(Developer(DEVELOPER_LEVEL_SPAM, "getWorkFromClientQueue returning %d\n", g_visportalindex));
  1075.     }
  1076.     s_ClientWorkQueueLock.LeaveMutex();
  1077.     return g_visportalindex;
  1078. }
  1079.